﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using OpenIddict.EntityFrameworkCore.Models;
using SageKing.Core.Extensions;
using SageKing.Database.Contracts;

namespace SageKing.OpenIddict.UI.Api;

public class ApplicationApiHttpClient
    : IApplicationApiService, IHttpClientAuthorization
{
    private readonly HttpClient _httpClient;
    private readonly IApplicationApiService applicationApiService;

    public readonly IOpenIddictToken _openIddictToken;

    public ApplicationApiHttpClient(IApplicationApiService applicationApiService,
        IHttpClientFactory httpClientFactory,
        IOpenIddictToken openIddictToken)
    {
        this.applicationApiService = applicationApiService ?? throw new ArgumentNullException(nameof(applicationApiService));

        _httpClient = httpClientFactory.CreateClient(HttpClientConsts.HttpClientIssuerKey) ?? throw new ArgumentNullException(nameof(httpClientFactory));

        _httpClient.CheckBaseAddress();
        _openIddictToken = openIddictToken;
    }

    public string Token { get; private set; }

    public bool AddAuthorizationToken(string token, bool addBearer = true)
    {
        this.Token = token;
        if (_httpClient.DefaultRequestHeaders.Contains(HttpClientConsts.HeaderAuthKey))
        {
            _httpClient.DefaultRequestHeaders.Remove(HttpClientConsts.HeaderAuthKey);
        }

        var tmpBearer = (addBearer ? HttpClientConsts.HeaderAuthBearer : "") + token;
        _httpClient.DefaultRequestHeaders.Add(HttpClientConsts.HeaderAuthKey, tmpBearer);
        return true;
    }

    public async Task InitAuthorizationToken(bool isClear = false)
    {
        if (Token.IsNullOrEmpty() || isClear)
        {
            Token = await _openIddictToken.GetTokenWithClientCredentialsAsync();
            AddAuthorizationToken(Token);
        }
    }

    public Task<string> CreateAsync(ApplicationViewModel model)
    {
        return applicationApiService.CreateAsync(model);
    }

    public Task DeleteAsync(string clientId)
    {
        return applicationApiService.DeleteAsync(clientId);
    }

    public Task<IEnumerable<ApplicationViewModel>> GetApplicationsAsync()
    {
        return applicationApiService.GetApplicationsAsync();
    }

    public Task<ApplicationViewModel> GetAsync(string clientId)
    {
        return applicationApiService.GetAsync(clientId);
    }

    public Task<ApplicationOptionsViewModel> GetOptionsAsync()
    {
        return applicationApiService.GetOptionsAsync();
    }

    public Task<PageBase<ApplicationViewModel>> GetPageAsync(PageBaseInput page)
    {
        return applicationApiService.GetPageAsync(page);
    }

    public Task<PageBase<ApplicationViewModel>> GetPage(PageBaseInput page, Expression<Func<OpenIddictEntityFrameworkCoreApplication, object>> orderby, bool orderByAsc = true)
    {
        return applicationApiService.GetPage(page, orderby, orderByAsc);
    }

    public Task<PageBase<ApplicationViewModel>> GetPage(PageBaseInput page, List<(bool, Expression<Func<OpenIddictEntityFrameworkCoreApplication, bool>>)> whereIf, Expression<Func<OpenIddictEntityFrameworkCoreApplication, object>> orderby, bool orderByAsc = true)
    {
        return applicationApiService.GetPage(page, whereIf, orderby, orderByAsc);
    }

    public async Task UpdateAsync(ApplicationViewModel model)
    {
        await InitAuthorizationToken();
        var url = "api/application";
        var rsp = await _httpClient.PutAsJsonAsync(url, model);
        if (rsp.StatusCode == HttpStatusCode.BadRequest)
        {
            var result = await rsp.Content.ReadAsStringAsync();
            throw new Exception(result);
        }
        var msg = rsp.EnsureSuccessStatusCode();

    }
}
